package com.mach.platform.sprider.getter;

import com.mach.platform.sprider.Conf;
import com.mach.platform.sprider.getter.DataLogService;
import com.mach.platform.sprider.mail.MailOperation;
import com.mach.platform.util.PairModel;
import com.mach.platform.util.SqlHelper;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.query.criteria.internal.predicate.NegatedPredicateWrapper;

import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class MainWork implements Runnable{


    private static  SqlHelper sqlHelper = null;
    private static  SqlHelper sqlHelperExt = null;
    private DataLogService dataLogService = null;



    public MainWork(){
        initBus();
    }
    private void initBus(){
//        Mysql数据库
        this.sqlHelper = DataCenter.sqlHelper;
        //DataLogService
        dataLogService = Conf.getMongoDbHelper();
//        dataLogService = NissanDataLogService.get(MongoDbJdbc.get());
        this.sqlHelperExt = DataCenter.sqlHelperExt;
    }

    @Override
    public void run() {
        int cnt = 0;
         while (true){
            ++cnt;
           try{
               this.work();
               this.cleanWin();

               Thread.sleep(500);

//               if(Thread.activeCount() > 500){
//                   Thread.sleep(1000*10);
//               }




           }catch (Exception e){
               e.printStackTrace();
           }
        }
    }

    private void cleanWin() {
//        select date_add(@dt, interval 1 day); -- add 1 day
//        select date_add(@dt, interval 1 hour); -- add 1 hour
//        select date_add(@dt, interval 1 minute); -- ...
//        select date_add(@dt, interval 1 second);
//        select date_add(@dt, interval 1 microsecond);
//        select date_add(@dt, interval 1 week);
//        select date_add(@dt, interval 1 month);
//        select date_add(@dt, interval 1 quarter);
//        select date_add(@dt, interval 1 year);

        try {
//            this.sqlHelper.update("insert into iot_dev_data_win_bak\n" +
//                    "select * \n" +
//                    "from iot_dev_data_win\n" +
//                    "where id>(select max(id) from iot_dev_data_win_bak)");

//            this.sqlHelper.update("DELETE from iot_dev_data_win \n" +
//                    " where the_time<date_sub(now(), interval 7 day) ");

//            this.sqlHelper.update(" update  iot_dev_cur_data_win set uptime=now() ");


//            this.sqlHelper.update("update iot_dev_cur_data_win set dvalue=null \n" +
//                    " where uptime<date_sub(now(), interval 60 second) ");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private List<GeneralDev> preDevs = new LinkedList<GeneralDev>();

    //开始抓取数据zzzzzzz
    public void work() {

        String sql2GetDevs = "select dev.id devId, dev.name name,dev.dev_type_id devTypeId,\n" +
                " dev.comm_addr commAddr,\n" +
                " type.prol prol,  \n" +
                " coll.id collId, coll.name collName," +
                " coll.value_addr collAddr, coll.value_addr_str collAddrStr,\n " +
                " coll.data_len collLen, coll.data_type collDataType,coll.unit collUnit,coll.fun_code collFunCode,coll.wait_time collWaitTime,coll.saver_num collSaverNum, \n" +
                " '' from iot_dev dev\n" +
                " LEFT JOIN iot_coll_items coll on dev.dev_type_id=coll.dev_type_id\n" +
                " LEFT JOIN iot_dev_type type on type.id=dev.dev_type_id \n" +
                " where 1=1 \n" +
//                " and dev.id in (161)" + // debug
//                " and dev.comm_addr like '192.168.0.185:102:1'" + // debug
//                " and (type.id in (68,78) or dev.id in (78))" +
//                " and (type.id in (77,71) or dev.id in (79))" +
                " and type.prol='GeneralModbusTCP' " + //debug
                " and coll.is_get=1 \n" +
                " order by devId,collId ";

        try {
            List<GeneralDev> curDevs = new LinkedList<GeneralDev>();

            Map<Object, Map<String, Object>> dbObj =
                    sqlHelper.queryPairModel(sql2GetDevs,
                            new PairModel("dev", "devId","coll",true));

//            log.info("devSize="+ dbObj.size());

            Set<Map.Entry<Object, Map<String, Object>>> allDevEntrys = dbObj.entrySet();

            for(Map.Entry<Object, Map<String, Object>> enery:  allDevEntrys){   //Map.Entry表示一种数据类型，里面包含了key、value。
                try {
                    Object key = enery.getKey();
                    Map<String, Object> devInfo = enery.getValue();

                    String prol = (String)devInfo.get("prol");

                    GeneralDev dev = null;

                    dev = DevFactory.getOrNew(devInfo,this.sqlHelper , this.dataLogService);

                    if(dev != null)dev.start();

                    curDevs.add(dev);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            this.preDevs  = curDevs;

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static boolean isOutRang(Map<String, Object> devInfoMap,Map<String, Object> coll, Object valueObj) throws SQLException {
        boolean result = false;

        Double down = 0.0;
        Double up = Double.MAX_VALUE;
        Integer devId = (Integer)devInfoMap.get("devId");
        Integer collId = (Integer)coll.get("collId");

        Map<String, Object> limtObj = sqlHelper.queryOne("select low_limit down, upper_limit up " +
                " from iot_limit " +
                " where 1=1" +
                "   and coll_id=" + collId +
                " and dev_id=" + devId);

        down = (Double) limtObj.get("down");
        up = (Double) limtObj.get("up");

        Double valueNum = null;

        if(valueObj instanceof Float){
            valueNum = ((Float)valueObj)* 1.0;
        }
        if(valueObj instanceof Double){
            valueNum = ((Double)valueObj);
        }
        if(valueObj instanceof Short){
            valueNum = ((Short)valueObj)* 1.0;
        }
        if(valueObj instanceof Integer){
            valueNum = ((Integer)valueObj)* 1.0;
        }

        if(valueNum != null && (down >= valueNum || valueNum >= up )){
            result = true;
        }else{
            result = false;
        }

        return result;
    }
    public static boolean isSend(Map<String, Object> devInfoMap,Map<String, Object> coll, Object valueObj) throws SQLException {
        boolean result = true;

        Integer collId = (Integer)coll.get("collId");
        Object oldValue = collValuMaps.get(collId);
        if(oldValue == null){
            result  = true;
        }else{

            if(oldValue .equals( valueObj )){
                result  = false;
            }
        }

        if(isOutRang(devInfoMap, coll, result)){//超限发
            result = true;
        }else{//范围内
            result  = false;
        }
        collValuMaps.put(collId, valueObj);

        Long lastSendTime = collSendTimeMaps.get(collId);
        if(lastSendTime == null)lastSendTime = 0l;
        long now = System.currentTimeMillis();
        long dt = now - lastSendTime;
        if(dt > 1000 * 60){ //无论超不超限或是变化，到时间则发送
            result = true;
        }

        if(result){
            collSendTimeMaps.put(collId, now);
        }

        return result;
    }

    private static Map<Integer, Object > collValuMaps = new HashMap<Integer, Object >();
    private static Map<Integer, Long > collSendTimeMaps = new HashMap<Integer, Long >();

    public static void addResultJustCur(Map<String, Object> devInfoMap,Map<String, Object> coll,Object result){
        Integer devId = Integer.parseInt(devInfoMap.get("devId").toString());
        String collName = (String)coll.get("collName");
        String collUnit = (String)coll.get("collUnit");
        try {
            if(Conf.isFliterData && (isOutRang(devInfoMap, coll, result) || result == null ) ){
                return;
            }
                sqlHelper.updateAsync(
                        "replace into iot_dev_cur_data_win" +
                                "(dev_id, data_type,dvalue,unit,uptime)" +
                                " value("+devId+", '"+collName+"', "+result+",'"+collUnit+"',now())");
            if(sqlHelperExt != null){       //控制数据是保存在那个数据库
                sqlHelperExt.updateAsync(
                        "replace into iot_dev_cur_data_win" +
                                "(dev_id, data_type,dvalue,unit,uptime)" +
                                " value("+devId+", '"+collName+"', "+result+",'"+collUnit+"',now())");
            }
            //this.dataLogService.addDataLogAsync(devId, new Date(), collName, result);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("error saveToDb... msg:" + e.getLocalizedMessage() + " devId=" + devId +  "dataType=" + collName);
        }
    }


    public static void addResultJustWin(Map<String, Object> devInfoMap,Map<String, Object> coll,Object result){
        Integer devId = Integer.parseInt(devInfoMap.get("devId").toString());
        String collName = (String)coll.get("collName");
        String commAddr = (String)devInfoMap.get("commAddr");
        Integer devTypeId = (Integer)devInfoMap.get("devTypeId");
        try {
            if(Conf.isFliterData && (isOutRang(devInfoMap, coll, result) || result == null)){
                return;
            }
                // 插入数据到 内存表，三个小时数据

                        sqlHelper.updateAsync(
                                "replace into iot_dev_data_win" +
                                        "(order_num,dev_id, the_time,data_type,dvalue)" +
                                        " value(1,"+devId+",DATE_FORMAT(now(),'%Y-%m-%d %H:00:00'), '"+collName+"', "+result+")");
//                        sqlHelper.updateAsync(
//                                "replace into iot_dev_data_win_bak" +
//                                        "(order_num,dev_id, the_time,data_type,dvalue)" +
//                                        " value(1," + devId + ",now(), '" + collName + "', " + result + ")");

                if(sqlHelperExt != null) {
//                    sqlHelperExt.updateAsync(
//                            "insert into iot_dev_data_win_bak" +
//                                    "(order_num,dev_id, the_time,data_type,dvalue)" +
//                                    " value(1," + devId + ",now(), '" + collName + "', " + result + ")");
                    sqlHelperExt.updateAsync(
                            "insert into iot_dev_data_win" +
                                    "(order_num,dev_id, the_time,data_type,dvalue)" +
                                    " value(1," + devId + ",now(), '" + collName + "', " + result + ")");
                }

            //this.dataLogService.addDataLogAsync(devId, new Date(), collName, result);
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("error saveToDb... msg:" + e.getLocalizedMessage() + " devId=" + devId +  "dataType=" + collName);
        }
    }

    public static void addResult(Map<String, Object> devInfoMap,Map<String, Object> coll,Object result){

        try {
//            sqlHelper.updateAsync(
//                    "replace into iot_dev_cur_data_win" +
//                            "(dev_id, data_type,dvalue,unit,uptime)" +
//                            " value("+devId+", '"+collName+"', "+result+",'"+collUnit+"',now())");
//
//            sqlHelper.updateAsync(
//                    "insert into iot_dev_data_win" +
//                            "(order_num,dev_id, the_time,data_type,dvalue)" +
//                            " value(1,"+devId+",now(), '"+collName+"', "+result+")");

            //this.dataLogService.addDataLogAsync(devId, new Date(), collName, result);

            addResultJustCur(devInfoMap, coll, result);
            addResultJustWin(devInfoMap, coll, result);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

